package com.lg.concurrent.schedule;

import java.util.Map;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CyclicBarrier;

/**
 * CountDownLatch与CyclicBarrier的区别：
 *
 * 1.前者工作线程协调同时执行是由外面的线程来协调的，而后者是有线程本身协调同时执行的；
 *
 * 2.前程await不能反复触发，后者可以反复触发，再一次执行汇总任务；
 *
 * 3.前者的count数字与线程的数量无关，同一个线程可以执行多次countDown，而后者count数字是与线程密切相关的，跟线程数量一致；
 *
 * 4.前者在子线程执行的时候不能执行别的任务，后者可以在初始化的时候传递一个barrierAction，
 * 子线程做完之后，可以执行barrierAction这个汇总的任务，barrierAction由最后一个进入屏障的线程执行
 *
 *
 *类说明：演示CyclicBarrier用法,共5个子线程，他们全部完成工作后，交出自己结果，
 *再被统一释放去做自己的事情，而交出的结果被另外的线程拿来拼接字符串
 *  [ˈsaɪklɪk] [ˈbæriər]
 */
public class CyclicBarrierDemo {
    static CyclicBarrier cyclicBarrier = new CyclicBarrier(5, new CollectThread());

    private static ConcurrentHashMap<String,Long> resultMap
            = new ConcurrentHashMap<>();//存放子线程工作结果的容器

    public static void main(String[] args) throws BrokenBarrierException, InterruptedException {
        for(int i=0;i<=4;i++){
            Thread thread = new Thread(new SubThread());
            thread.start();
        }
    }

    /**
     * 汇总的任务
     */
    private static class CollectThread implements Runnable{
        @Override
        public void run() {
            StringBuilder result = new StringBuilder();
            for(Map.Entry<String,Long> workResult:resultMap.entrySet()){
            	result.append("["+workResult.getValue()+"]");
            }
            System.out.println("threadName:" + Thread.currentThread().getName() + ", result = "+ result);
            System.out.println("do other business........");
        }
    }

    /**
     * 相互等待的子线程
     */
    private static class SubThread implements Runnable{
        @Override
        public void run() {
        	long id = Thread.currentThread().getId();
            resultMap.put(Thread.currentThread().getId()+"",id);
            try {
                Thread.sleep(1000+id);
                System.out.println("threadName:" + Thread.currentThread().getName() + ", Thread_"+id+" ....do something ");
                cyclicBarrier.await(); //调用之后，当前的线程就在cyclicBarrier上等待，直到所有的线程都执行完之后，再继续执行下面的代码，这个await可以反复调用
            	Thread.sleep(1000+id);
                System.out.println("threadName:" + Thread.currentThread().getName() + ", Thread_"+id+" ....do its business ");
                cyclicBarrier.await(); // 再次执行，再一次汇总
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}